import {
  AfterContentInit,
  Component,
  ContentChildren,
  Input,
  OnDestroy,
  OnInit,
  QueryList,
  TemplateRef
} from '@angular/core';
import { Subscription } from 'rxjs';

import { toBoolean } from '../core/util/convert';

import { ApesStepComponent } from './apes-step.component';

export type ApesDirectionType = 'horizontal' | 'vertical';
export type ApesStatusType = 'wait' | 'process' | 'finish' | 'error' | 'string'| 'stringWait' | 'stringProcess';
export type ApesSizeType = 'default' | 'small';

@Component({
  selector           : 'apes-steps',
  preserveWhitespaces: false,
  templateUrl        : './apes-steps.component.html'
})
export class ApesStepsComponent implements OnInit, OnDestroy, AfterContentInit {
  private _status: ApesStatusType = 'process';
  private _current = 0;
  private _size: ApesSizeType = 'default';
  private _direction: ApesDirectionType = 'horizontal';
  private stepsSubscription: Subscription;
  prefixCls = 'apes-steps';
  stepsClassMap: object;
  showProcessDot = false;
  customProcessDotTemplate: TemplateRef<{ $implicit: TemplateRef<void>, status: string, index: number }>;
  @ContentChildren(ApesStepComponent) steps: QueryList<ApesStepComponent>;

  @Input() set apesSize(value: ApesSizeType) {
    this._size = value;
    this.updateClassMap();
  }

  get apesSize(): ApesSizeType {
    return this._size;
  }

  @Input()
  set apesDirection(value: ApesDirectionType) {
    this._direction = value;
    this.updateClassMap();
    this.updateChildrenSteps();
  }

  get apesDirection(): ApesDirectionType {
    return this._direction;
  }

  @Input()
  set apesProgressDot(value: boolean | TemplateRef<{ $implicit: TemplateRef<void>, status: string, index: number }>) {
    if (value instanceof TemplateRef) {
      this.showProcessDot = true;
      this.customProcessDotTemplate = value;
    } else {
      this.showProcessDot = toBoolean(value);
    }
    this.updateChildrenSteps();
    this.updateClassMap();
  }

  @Input()
  set apesStatus(status: ApesStatusType) {
    this._status = status;
    this.updateChildrenSteps();
  }

  get apesStatus(): ApesStatusType {
    return this._status;
  }

  @Input()
  set apesCurrent(current: number) {
    this._current = current;
    this.updateChildrenSteps();
  }

  get apesCurrent(): number {
    return this._current;
  }

  updateClassMap(): void {
    this.stepsClassMap = {
      [ `${this.prefixCls}-${this.apesDirection}` ]: true,
      [ `${this.prefixCls}-label-horizontal` ]   : this.apesDirection === 'horizontal',
      [ `${this.prefixCls}-label-vertical` ]     : this.showProcessDot && (this.apesDirection === 'horizontal'),
      [ `${this.prefixCls}-dot` ]                : this.showProcessDot,
      [ `${this.prefixCls}-small` ]              : this.apesSize === 'small'
    };
  }

  updateChildrenSteps = () => {
    if (this.steps) {
      this.steps.toArray().forEach((step, index, arr) => {
        step.outStatus = this.apesStatus;
        step.showProcessDot = this.showProcessDot;
        if (this.customProcessDotTemplate) {
          step.customProcessTemplate = this.customProcessDotTemplate;
        }
        step.direction = this.apesDirection;
        step.index = index;
        step.currentIndex = this.apesCurrent;
        step.last = arr.length === index + 1;
        step.updateClassMap();
      });
    }
  }

  ngOnInit(): void {
    this.updateClassMap();
  }

  ngOnDestroy(): void {
    if (this.stepsSubscription) {
      this.stepsSubscription.unsubscribe();
      this.stepsSubscription = null;
    }
  }

  ngAfterContentInit(): void {
    Promise.resolve().then(() => this.updateChildrenSteps());
    if (this.steps) {
      this.stepsSubscription = this.steps.changes.subscribe(this.updateChildrenSteps);
    }
  }
}
